package com.tomz.xatomic;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.util.StringUtils;

/**
 * 数据源切面, 不添加注解将使用默认数据源。<br>
 * 注意：
 * <p>
 *    设置切面次序，最高优先级，不然的话会在@Transactional的切面之后执行，导致@DynamicDataSource注解失效<br>
 *    Transactional注解的切面使用cglib动态代理，在方法执行前获取dataSource的connection并使用ThreadLocal线程持有，<br>
 *    所以如果该切面优先级低于事务的优先级，导致切换数据源无效，因为connection在切换之前已经被取出并且不是切换后数据源的connection
 * </p>
 *  注意Order序号要小于{@link  org.springframework.aop.interceptor.ExposeInvocationInterceptor}, PriorityOrdered.HIGHEST_PRECEDENCE + 1
 *
 * @author ZHUFEIFEI
 */
@Order(-1000)
@Aspect
public class DynamicDataSourceAspect {

    private final Logger log = LoggerFactory.getLogger(getClass());

    /**
     * <code>@annotation(注解参数名称)</code>
     * @param point
     * @param dynamicDataSource
     */
    @Before("@annotation(dynamicDataSource)")
    public void determineDataSource(JoinPoint point, DynamicDataSource dynamicDataSource) {
        String key = dynamicDataSource.value();
        log.debug("determine data source {} => {}", point.getSignature().getName(), key);
        if (StringUtils.hasLength(key)) {
            DynamicDataSourceContextHolder.set(key);
        }
    }

    @After("@annotation(dynamicDataSource)")
    public void clearDataSource(JoinPoint point, DynamicDataSource dynamicDataSource) {
        String key = dynamicDataSource.value();
        log.debug("clear data source {} => {}", point.getSignature().getName(), key);
        DynamicDataSourceContextHolder.remove();
    }
}
